package demoscene;

import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.util.Random;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JFrame;
import javax.swing.JPanel;

/**
 *
 * @author Luis
 */
public class Fire {
    int mSize;
    int mWidth;
    int mHeight;
    int mFireBuffer[][];
    int mImageBuffer[];
    int mCoolingBuffer[];
    int mCoolingOffset;
    
    int[] mPalette;
    Random mRandom;
    
    int RGB(int r, int g, int b, int a){
        return ((a & 0xFF) << 24) | ((r & 0xFF) << 16) | ((g & 0xFF) << 8) | (b & 0xFF);
    }
      
    public Fire(int width, int height){
        mRandom = new Random();
        mWidth = width;
        mHeight = height;
        mSize = width * height;
        mFireBuffer = new int[2][mSize];
        mImageBuffer = new int[mSize];
        mCoolingBuffer = new int[mSize];
        
        
        for (int i = 0 ; i < mSize ; i++)
            mCoolingBuffer[i] = mRandom.nextInt(5);
        
        mCoolingOffset = 0;
        
        mPalette = new int[256];
        for (int i = 0 ; i < 64 ; i++)
            mPalette[i] = RGB(4 * i, 0, 0, 255);
        for (int i = 0 ; i < 64 ; i++)
            mPalette[i + 64] = RGB(255, 2 * i, 0, 255);
        for (int i = 0 ; i < 96 ; i++)
            mPalette[i + 128] = RGB(255, 128 + 4 * i / 3, 0, 255);
        for (int i = 0 ; i < 32 ; i++)
            mPalette[i + 224] = RGB(255, 255, 8 * i, 255);
//        for (int i = 0 ; i < 32 ; i++)
//            mPalette[i] = RGB(8 * i, 0, 0, 255);
//        for (int i = 0 ; i < 32 ; i++)
//            mPalette[i + 32] = RGB(255, 4 * i, 0, 255);
//        for (int i = 0 ; i < 48 ; i++)
//            mPalette[i + 64] = RGB(255, 128 + 8 * i / 3, 0, 255);
//        for (int i = 0 ; i < 16 ; i++)
//            mPalette[i + 112] = RGB(255, 255, 16 * i, 255);        
    }
 
    public int[] render(){
        for (int i = mSize - mWidth ; i < mSize ; i++)
            mFireBuffer[1][i] = 255 * mRandom.nextInt(2);        
        for (int i = mWidth ; i < mSize - mWidth ; i++){
//            int p = (mFireBuffer[1][i + 1] + mFireBuffer[1][i - 1] + mFireBuffer[1][i + mWidth] + mFireBuffer[1][i - mWidth]) / 4;
            int p = (mFireBuffer[1][i + 1] + mFireBuffer[1][i - 1] + mFireBuffer[1][i + mWidth]) / 3;
            p -= mCoolingBuffer[(i + mCoolingOffset) % mCoolingBuffer.length];
            if (p < 0)
                p = 0;
            mFireBuffer[0][i - mWidth] = p;
        }
        for (int i = 0 ; i < mSize ; i++)
            mImageBuffer[i] = mPalette[mFireBuffer[0][i]];
        
        for (int i = 0 ; i < mPalette.length - mWidth ; i++)
            mImageBuffer[i] = mPalette[i];
        System.arraycopy(mFireBuffer[0], 0, mFireBuffer[1], 0, mSize);
        mCoolingOffset += mWidth;
        return mImageBuffer;
    }
    
    public static void main(String[] args) {
        int WIDTH = 256;
        int HEIGHT = 256;
        
        //preparamos panel para mostrar el efecto
        JFrame frame = new JFrame();
        JPanel panel = (JPanel)frame.getContentPane();
        panel.setPreferredSize(new Dimension(WIDTH, HEIGHT));  //ajustamos tamaño a WIDTH x HEIGHT
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);  //al cerrar el frame -> se cierra la aplicación
        frame.pack();  //compactamos el frame (se ajusta tamaño del frame a contenido)
        frame.setLocationRelativeTo(null);  //frame al centro de la pantalla
        frame.show();  //mostramos el frame        
        
        BufferedImage image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);  //imagen
        //creamos la clase que realizará el render del efecto (ver clase "Plasma")
        //pasamos como parámetro el ancho y el alto
        Fire effect = new Fire(WIDTH, HEIGHT);
        
        //blucle de animación        
        while (true){
            int[] mBufferEffect = effect.render();  //calculamos frame y volcamos resultado en buffer temporal
            Graphics g = panel.getGraphics();  //tomamos "canvas" del panel (en donde vamos a dibujar)
            if (g != null){
                image.setRGB(0, 0, WIDTH, HEIGHT, mBufferEffect, 0, WIDTH);  //volcamos buffer sobre imágen temporal
                g.drawImage(image, 0, 0, WIDTH, HEIGHT, null);  //dibujamos imagen temporal sobre el "canvas"
                g.dispose();  //liberamos el "canvas"
            }
            try {
                Thread.sleep(10);
            } catch (InterruptedException ex) {
                Logger.getLogger(Fire.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }     
}
